/*
 * kmean_main.cpp
 *
 *  Created on: Mar 06, 2011
 *      Author: tqlong
 */

#include <iostream>
#include <boost/program_options.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <ctime>
#include <cassert>
#include <armadillo>

#include <vector>
#include <fstream>
#include <iostream>

#include "kmean.h"
#include "common/armavec.h"

namespace po = boost::program_options;
po::options_description desc("Allowed options");
po::variables_map vm;

void process_options(int argc, char** argv);

template <typename vec>
void kmean()
{
  Dataset<vec> data;
  data.load(vm["data"].as<std::string>(), arma::arma_ascii);
  //data.normalize();
  //data.print();

  std::cout<< "n = " << data.size()<<"\n";

  int nc = vm["nc"].as<int>();
  int maxiter = vm["iter"].as<int>();
  std::vector<double> p;
  p.push_back(maxiter);

  typedef KMean<vec, Dataset<vec> > Functional;
  Functional F(data, nc);
  F.setParams(p);
  F.optimize();

  int n = data.size();
  for (int i = 0; i< n; i++) {
    std::cout << "sample " << i << " class " << F.y(i) << "\n";
  }

  for (int i = 0; i < nc; i++) {
    std::cout << "center[" << i << "]=\n" << F.center(i) << "\n";
  }
}

template <typename vec>
void generateData()
{
  int n = vm["n"].as<int>(); // #points in each cluster
  int nc = vm["nc"].as<int>(); // #clusters
  int d = vm["d"].as<int>();
  double r = vm["r"].as<double>();
  Dataset<vec> data;
  for (int c = 0; c < nc; c++) {
    vec center(d);
    center.randn();
    center *= 10.0;
    std::cerr << "c = " << c << " center=\n" << center;
    for (int i = 0; i < n; i++) {
      vec x(d);
      x.randn();
      x *= r;
      x += center;
      data.push_back(x);
    }
  }
  data.save(vm["data"].as<std::string>(), arma::arma_ascii);
}

int main(int argc, char** argv) {
  process_options(argc, argv);
  if (vm.count("help") || !vm.count("data")) {
    std::cout << desc << "\n";
    return 0;
  }
  typedef ArmaVec vec;
  if (vm.count("gen")) {
    if (vm.count("seed"))
      srand(time(NULL));
    generateData <vec> ();
    return 0;
  }

  boost::posix_time::ptime time_start(boost::posix_time::microsec_clock::local_time());

  kmean<vec> ();

  boost::posix_time::ptime time_end(boost::posix_time::microsec_clock::local_time());
  boost::posix_time::time_duration duration(time_end - time_start);
  std::cerr << "Duration = " << duration << "\n";
  return 0;
}

void process_options(int argc, char** argv)
{
  desc.add_options()
    ("help", "produce this usage")
    ("data", po::value<std::string>(), "file contains training samples")
    ("gen", "generate random data")
    ("seed", "using different random seed")
    ("n", po::value<int>()->default_value(10), "number of points")
    ("nc", po::value<int>()->default_value(3), "number of centers")
    ("d", po::value<int>()->default_value(2), "input dimension")
    ("r", po::value<double>()->default_value(1.0), "cluster radius")
    ("lambda", po::value<double>()->default_value(1.0), "regularized parameter")
    ("iter", po::value<int>()->default_value(10), "maximum number of iterations")
    ("eta", po::value<double>()->default_value(0.5), "learning rate")
    ("mesh", po::value<std::string>()->default_value("mesh"), "mesh files prefix")
    ;
  po::store(po::parse_command_line(argc, argv, desc), vm);
  po::notify(vm);
}
